#include "Thread.hpp"
#include "BlockQueue.hpp"
#include <vector>
#include "Task.hpp"
#include <ctime>

using namespace std;
using BlockQueue_t = BlockQueue<Task>;

void *ProTask(void *args)
{
    BlockQueue_t *bq = static_cast<BlockQueue_t *>(args);
    while (true)
    {
        sleep(1);
        int a = rand() % 10 + 1;
        int b = rand() % 5 + 1;
        Task t(a, b);
        bq->Enqueue(t);
        cout << "productor push task, " << "a: " << a << " b: " << b << endl;
    }
}
void *ConTask(void *args)
{
    BlockQueue_t *bq = static_cast<BlockQueue_t *>(args);
    while (true)
    {
        Task t;
        bq->Outqueue(&t);
        t.Excute();
        cout << "consumer: " << t.getRet() << endl;
    }
}
void StartPro(vector<pthread_t> *tptr, BlockQueue_t *bq)
{
    pthread_t tid;
    int n = pthread_create(&tid, nullptr, ProTask, (void *)bq);
    if (n == 0)
        cout << "create productor success" << endl;
    tptr->emplace_back(tid);
}
void StartCon(vector<pthread_t> *tptr, BlockQueue_t *bq)
{
    pthread_t tid;
    int n = pthread_create(&tid, nullptr, ConTask, (void *)bq);
    if (n == 0)
        cout << "create consumer success" << endl;
    tptr->emplace_back(tid);
}

void WaitAll(vector<pthread_t> threads)
{
    for (auto &thread : threads)
    {
        pthread_join(thread, nullptr);
    }
}
int main()
{
    srand(time(0));
    vector<pthread_t> threads;
    BlockQueue_t *bq = new BlockQueue_t(5);
    StartPro(&threads, bq);
    StartCon(&threads, bq);
    WaitAll(threads);
    return 0;
}

// using namespace std;
// using BlockQueue_t = BlockQueue<int>;

// void *ProTask(void *args)
// {
//     BlockQueue_t *bq = static_cast<BlockQueue_t*>(args);
//     int cnt = 1;
//     while (true)
//     {
//         sleep(1);
//         bq->Enqueue(cnt);
//         cout << "productor: " << cnt << endl;
//         cnt++;
//     }
// }
// void *ConTask(void *args)
// {
//     BlockQueue_t *bq = static_cast<BlockQueue_t*>(args);
//     while (true)
//     {
//         int data;
//         bq->Outqueue(&data);
//         cout << "consumer: " << data << endl;
//     }
// }
// void StartPro(vector<pthread_t> *tptr, BlockQueue_t &bq)
// {
//     pthread_t tid;
//     int n = pthread_create(&tid, nullptr, ProTask, (void*)&bq);
//     if(n == 0) cout << "create productor success" << endl;
//     tptr->emplace_back(tid);
// }
// void StartCon(vector<pthread_t> *tptr, BlockQueue_t &bq)
// {
//     pthread_t tid;
//     int n = pthread_create(&tid, nullptr, ConTask, (void*)&bq);
//     if(n == 0) cout << "create consumer success" << endl;
//     tptr->emplace_back(tid);
// }

// void WaitAll(vector<pthread_t> threads)
// {
//     for(auto &thread:threads)
//     {
//         pthread_join(thread, nullptr);
//     }
// }
// int main()
// {
//     vector<pthread_t> threads;
//     BlockQueue_t *bq = new BlockQueue_t(5);
//     StartPro(&threads, *bq);
//     StartCon(&threads, *bq);
//     WaitAll(threads);
//     return 0;
// }

// using namespace thread_ns;
// using BlockQueue_t = BlockQueue<int>;

// void ProTask(BlockQueue_t &bq)
// {
//     int cnt = 1;
//     while (true)
//     {
//         sleep(1);

//         bq.Enqueue(cnt);
//         cout << "productor: " << cnt << endl;
//         cnt++;
//     }
// }
// void ConTask(BlockQueue_t &bq)
// {
//     while (true)
//     {
//         int data;
//         bq.Outqueue(&data);
//         cout << "consumer: " << data << endl;
//     }
// }
// void StartPro(vector<Thread<BlockQueue_t>> *threads, BlockQueue_t &bq)
// {
//     string name = "Productor";
//     threads->emplace_back(ProTask, bq, name);
// }
// void StartCon(vector<Thread<BlockQueue_t>> *threads, BlockQueue_t &bq)
// {
//     string name = "Consumer";
//     threads->emplace_back(ConTask, bq, name);
// }
// void StartAll(vector<Thread<BlockQueue_t>> threads)
// {
//     for (auto &t : threads)
//     {
//         t.Start();
//     }
// }

// void WaitAll(vector<Thread<BlockQueue_t>> threads)
// {
//     for (auto &t : threads)
//     {
//         t.Join();
//     }
// }
// int main()
// {
//     vector<Thread<BlockQueue_t>> threads;
//     BlockQueue_t *bq = new BlockQueue_t(5);
//     StartPro(&threads, *bq);
//     StartCon(&threads, *bq);
//     StartAll(threads);
//     WaitAll(threads);
//     return 0;
// }